<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>MCAS Explorer</title>
        <meta http-equiv="Content-Script-Type" content="text/javascript">
        <script type="text/javascript" src="protovis-d3.2.js"></script>
        <script type="text/javascript" src="https://www.google.com/jsapi"></script>
        <script type="text/javascript" src="../../../../..//Desktop/My Dropbox/edu/visualization/javascript/data/Northampton MCAS datatable.js"></script>
        <!-- at home, src="../../../../..//Desktop/My Dropbox/edu/visualization/javascript/data/Northampton MCAS datatable.js" --> 
        <!-- at work, src="file:///C:/Documents and Settings/dolsson/Desktop/My Dropbox/edu/visualization/javascript/data/Northampton MCAS datatable.js" -->
        <script type="text/javascript">
            google.load('visualization', '1', {'packages':['corechart']});
            google.setOnLoadCallback(prepData);

            var data;  // global data set (DataTable)
            var subjects;  // subjects (Array)
            var grades;  // grade levels for each subject (2-column DataTable)
            var years;  // all represented years (Array)

            function prepData() {
                defineData();
                subjects = data.getDistinctValues(col.subject);
                grades = google.visualization.data.group(data, [col.subject, col.grade], []);
                years = data.getDistinctValues(col.year).map(Number);
                plot = TimeSeries(400, 300);
                refreshSubject();
                refreshGrade();
                //drawHistogram(2010);
            }
        </script>
        <style type="text/css">
            .form { text-align: right; vertical-align: top; padding-bottom: 10px }
            .radio { text-align: left }
        </style>
    </head>
    <body>
        <h1>MCAS Explorer</h1>

        <table>
            <tr>
                <td style="vertical-align: top; padding-right: 0.25in">
                    <form>
                        <table>
                            <tr>
                                <th class="form">
                                    Northampton
                                </th>
                            </tr>
                            <tr>
                                <td class="form">
                                    <select id="subject_select" multiple onchange="newSubject()"></select>
                                </td>
                            </tr>
                            <tr>
                                <td class="form">
                                    <label>grade 
                                        <select id="grade_select" multiple onchange="newGrade()"  class="form"></select>
                                    </label>
                                </td>
                            </tr>
                            <tr>
                                <td class="form" style="text-align: left">
                                    <label><input type="radio" name="plot" value="time series" checked onchange="changePlot(this.value)">time series</label><br>
                                    <label><input type="radio" name="plot" value="time series grade grid" onchange="changePlot(this.value)">time series - grades</label>
                                </td>
                            </tr>
                        </table>
                    </form>
                </td>
                <td id="main_plot_el" style="width: 440px; height: 330px"></td>
            </tr>
        </table>
        <!-- td id="side_plot_el" style="width: 320px; height: 220px; vertical-align: bottom; padding-left: 20px"></td -->

<script type="text/javascript">

// Establish global variables for select controls.
var subjectSelect = document.getElementById("subject_select");
var gradeSelect = document.getElementById("grade_select");
var yearSelect = document.getElementById("year_select");

// Current plot.
var plot;

function changePlot(plotType) {
    switch (plotType) {
        case 'time series':
            plot = TimeSeries(400, 300);
            break;
        case 'time series grade grid':
            plot = Grid(0, grades);
            break;
    }
}

// Retrieve selected options for a menu.
function allSelected(menu) {
    var list = [];
    for (var child = 0; child < menu.childNodes.length; child++) {
        if (menu.childNodes[child].selected) {
            list.push(menu.childNodes[child].value);
        }
    }
    return list;
}

// New subject selection.
function newSubject() {
    refreshGrade();
    if (subjectSelect.value && gradeSelect.value)
        plot.draw();
    else
        plot.delete();
}

// New grade selection.
function newGrade() {
    if (subjectSelect.value && gradeSelect.value)
        plot.draw();
    else
        plot.delete();
}

// Refresh subject menu.
function refreshSubject() {
    var currentSelection = allSelected(subjectSelect);  // save current selection
    while (subjectSelect.firstChild)  // remove children
        subjectSelect.removeChild(subjectSelect.firstChild);
    var subjects = data.getDistinctValues(col.subject);
    for (var iSubj in subjects) {  // create new children
        var option = document.createElement('option');
        option.innerHTML = subjects[iSubj];
        if (currentSelection.indexOf(subjects[iSubj]) != -1)  // a previously selected value
            option.setAttribute('selected','');
        subjectSelect.appendChild(option);
    }
}
// Refresh grade menu.
function refreshGrade() {
    var currentSubjects = allSelected(subjectSelect);
    if (currentSubjects) {
        var currentSelection = allSelected(gradeSelect).map(Number);  // save current selection
        while (gradeSelect.firstChild)  // remove children
            gradeSelect.removeChild(gradeSelect.firstChild);
        var newGrades = [];  // new list of grades
        for (var iSubject in currentSubjects) {
            var gradeRows = grades.getFilteredRows([{column: 0, value: currentSubjects[iSubject]}]);
            for (var iRowIndex in gradeRows) {
                var newGrade = grades.getValue(gradeRows[iRowIndex], 1);
                if (!newGrades.some(function (grade) {return grade == newGrade}))
                    newGrades.push(newGrade);
            }
        }
        newGrades.sort(function (a, b) {return a - b});
        for (iGrade in newGrades) {  // create new children
            var option = document.createElement('option');
            option.innerHTML = newGrades[iGrade];
            if (currentSelection.indexOf(newGrades[iGrade]) != -1)  // a previously selected value
                option.setAttribute('selected','');
            gradeSelect.appendChild(option);
        }
    }
}

// Refresh year menu.
// [This is out of date. Cf other refresh functions.]
function refreshYear() {
    var subject = subjectSelect.value;
    var grade = gradeSelect.value;
    if (grade) {
        var currentValue = yearSelect.value;  // save current value
        while (yearSelect.firstChild)  // remove children
            yearSelect.removeChild(yearSelect.firstChild);
        for (var year in MCAS[subject][grade]) {  // create new children
            var option = document.createElement('option');
            option.innerHTML = year;
            if (year == currentValue)  // preselect if same value
                option.setAttribute('selected','');
            yearSelect.appendChild(option);
        }
    }
}

function Plot(w, h) {
    this.width = w;
    this.height = h;
    this.delete = Plot_delete;
    this.draw = (function () {});
}

function Plot_delete() {
    if (this.vis) {
        var canvas = this.vis.canvas();
        while (canvas.firstChild)
            canvas.removeChild(canvas.firstChild);
        delete this.vis;
    }
}

function TimeSeries(w, h) {
    var ts = new Plot(w, h);
    ts.x = new pv.Scale.ordinal().domain(years).split(0, ts.width);
    ts.y = new pv.Scale.linear().domain(0, 100).range(0, ts.height);
    ts.getData = TimeSeries_getData;
    ts.draw = TimeSeries_draw;
    return ts;
}


function TimeSeries_getData() {
    // Filter and aggregate data. Return true if we got some.
    this.subjects = allSelected(subjectSelect);
    this.grades = allSelected(gradeSelect).map(Number);
    // Find row indexes for qualifying records.
    var indices = [];
    for (iSubj in this.subjects) {
        for (iGrade in this.grades) {
            var newIndices = data.getFilteredRows([
                    {column: col.subject, value: this.subjects[iSubj]},
                    {column: col.grade, value: this.grades[iGrade]},
                    {column: col.cpi, minValue: 0} ]);
            indices = indices.concat(newIndices)
                .sort(function (a, b) {return a - b})
                .filter(function (val, index, array) {return index == 0 || val != array[index - 1]});
        }
    }
    var filtered = new google.visualization.DataView(data);
    filtered.setRows(indices);
    // Use a DataTable as the data series.
    this.series = google.visualization.data.group(filtered, [col.year], [{column: col.cpi, aggregation: pv.mean, type: 'number', label: 'CPI', id: 'cpi'}]);
    return this.series.getNumberOfRows() > 0;
}

function TimeSeries_draw() {
    var our = this;
    if (this.getData()) {
        this.vis = new pv.Panel()
            .canvas('main_plot_el')
            .width(our.width)
            .height(our.height)
            .top(10)
            .bottom(20)
            .left(40)
            .strokeStyle('lightgray')
            ;
        this.vis.add(pv.Rule)
            .data(pv.range(0,110,10))
            .bottom(function(d) {return our.y(d)})
            .strokeStyle('lightgray')
            .anchor('left').add(pv.Label)
            .text(function(d) {return d})
            ;
        this.vis.anchor('left').add(pv.Label)
            .text('CPI')
            .textAngle(- Math.PI / 2)
            .left(-30)
            .textAlign('center')
            .font('14px sans-serif')
            ;
        this.vis.add(pv.Line)
            .data(our.series.getSortedRows(0))
            .left(function(r) {return our.x(our.series.getValue(r, 0))})
            .bottom(function(r) {return our.y(our.series.getValue(r, 1))})
            .add(pv.Dot)
            ;
        this.vis.add(pv.Label)
            .data(our.series.getSortedRows(0))
            .left(function(r) {return our.x(our.series.getValue(r, 0))})
            .bottom(-20)
            .textAlign('center')
            .text(function(r) {return our.series.getValue(r, 0)})
            ;
        this.vis.render();
    }
};

function Grid(smallPlot, dimension) {
    if (dimension === grades) {
        var g = new Plot(400, 200);
        g.rows = [[3, 4, 5, 6], [7, 8, 9, 10]];
        g.getData = Grid_getDataTimeSeriesGrades;
        g.draw = Grid_drawTimeSeriesGrades;
        return g;
    }
}

function Grid_getDataTimeSeriesGrades() {
    // Filter and aggregate data. Return true if we get some.
    this.subjects = allSelected(subjectSelect);
    // Find row indexes for qualifying records.
    var indices = [];
    for (iSubj in this.subjects) {
        var newIndices = data.getFilteredRows([
                {column: col.subject, value: this.subjects[iSubj]},
                {column: col.cpi, minValue: 0} ]);
        indices = indices.concat(newIndices)
            .sort(function (a, b) {return a - b})
            .filter(function (val, index, array) {return index == 0 || val != array[index - 1]});
    }
    var filtered = new google.visualization.DataView(data);
    filtered.setRows(indices);
    // Use a DataTable as the data series.
    this.series = google.visualization.data.group(filtered, [col.grade, col.year], [{column: col.cpi, aggregation: pv.mean, type: 'number', label: 'CPI', id: 'cpi'}]);
    return this.series.getNumberOfRows() > 0;
}

function Grid_drawTimeSeriesGrades() {
    var our = this;
    this.getData();
    // our.series should have columns: grade; year; average cpi.
    this.vis = new pv.Panel()
        .canvas('main_plot_el')
        .width(our.width)
        .height(our.height)
        ;
    this.vis.add(pv.Layout.Grid)
        .rows(our.rows)
        .cell.add(pv.Panel)
        .anchor('bottom').add(pv.Label)
        .text(function (grade) {return grade})
        .parent.add(pv.Line)
        .data(function (grade) {
                return our.series.getFilteredRows([{column: 0, value: grade}]);
                })
        .left(function (row) {return (pv.Scale.ordinal(years).split(0, 100))(our.series.getValue(row, 1))})
        .bottom(function (row) {
                return (pv.Scale.linear(0, 100).range(0, 100))(our.series.getValue(row, 2));
                })
        .root.render()
        ;
}


function drawHistogram(year) {
    var w = 300;
    var h = 200;
    var hist = new pv.histogram(MCAS[plot.subject][plot.grade][year], function(d) {return d[8]});
    var bins = hist.bins([0, 25, 50, 75, 100, 125]);
    var x = new pv.Scale.ordinal([0, 25, 50, 75, 100]).splitBanded(0, w);
    var y = new pv.Scale.linear(0, pv.max(bins, function(b) {return b.y})).range(0, h);
    var vis = new pv.Panel()
        .canvas('side_plot_el')
        .width(w)
        .height(h)
        .bottom(20)
        .left(20)
        .strokeStyle('lightgray');
    vis.add(pv.Rule)
        .data(y.ticks())
        .bottom(function(t) {return y(t)})
        .strokeStyle('lightgray')
        .anchor('left').add(pv.Label)
        .text(function(t) {return y.tickFormat(t)})
        ;
    vis.add(pv.Bar)
        .data(bins)
        .left(function(b) {return x(b.x)})
        .width(x.range().band)
        .bottom(0)
        .height(function(b) {return y(b.y)})
        .root.add(pv.Label)
        .data(bins)
        .textAlign('center')
        .left(function(b) {return x(b.x) + 0.5 * x.range().band})
        .textBaseline('top')
        .bottom(0)
        .text(function(b) {return b.x})
        ;
    vis.render();
}

</script>
</body>
</html>
